feat: pair trezor passphrase hidden wallets - #1142
Merged
Merged
Conversation
… scope of this branch
…ction, doesn't exist when it's called and the mismatch path tears down the session before a retry
…eId in it.deviceIds } and unconditionally writes pairedWalletId = wallet.id, so a wallets emission that does not yet contain the just-added hidden wallet resets the paired identity back to the standard wallet.
…se POST, so a failed release still leaves the stale session id cached.
jvsena42
marked this pull request as ready for review
August 10, 2026 10:05
Greptile SummaryThe PR adds independently tracked Trezor hidden-wallet identities and passphrase-based session restoration while preserving wallet-scoped balances, activity, labels, signing, and removal.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| app/src/main/java/to/bitkit/repositories/HwWalletRepo.kt | Moves hardware-wallet aggregation, watcher lifecycle, signing, and removal to wallet-identity scope; the previously reported multi-transport removal issue is addressed. |
| app/src/main/java/to/bitkit/repositories/TrezorRepo.kt | Persists multiple identities per physical device and manages passphrase-bound sessions while atomically filtering scoped removals. |
| app/src/main/java/to/bitkit/services/TrezorBridgeTransport.kt | Clears released sessions and retries acquisition after refreshing a stale Bridge session. |
| app/src/main/java/to/bitkit/viewmodels/TransferViewModel.kt | Integrates passphrase restoration and identity verification into hardware-wallet signing. |
| app/src/main/java/to/bitkit/ui/sheets/hardware/HwConnectViewModel.kt | Adds passphrase-wallet pairing, duplicate handling, and known-device discovery fallback. |
| app/src/main/java/to/bitkit/ui/screens/transfer/hardware/HwPassphrasePromptSheet.kt | Adds the intentionally unmasked, screenshot-protected passphrase prompt used to restore signing sessions. |
Sequence Diagram
sequenceDiagram
participant UI as Hardware Wallet UI
participant HW as HwWalletRepo
participant TR as TrezorRepo
participant Device as Trezor
participant Store as HwWalletStore
UI->>HW: connectWithPassphrase(deviceId, passphrase)
HW->>TR: set/connect passphrase wallet mode
TR->>Device: Open fresh passphrase session
Device-->>TR: Features and account keys
TR->>Store: Persist identity by derived wallet ID
TR-->>HW: Connected wallet identity
HW-->>UI: Add or select hidden-wallet tile
UI->>HW: Sign from wallet ID
alt matching session is live
HW->>Device: Sign transaction
else session is absent or belongs to another identity
UI->>HW: reconnectWithPassphrase(walletId, passphrase)
HW->>TR: Open fresh passphrase session
TR->>Device: Read account keys
alt derived wallet ID matches
HW->>Device: Sign transaction
else derived wallet ID differs
HW->>TR: Disconnect stray session
HW-->>UI: Reject passphrase mismatch
end
end
Reviews (3): Last reviewed commit: "fix: passphrase should not gate pending ..." | Re-trigger Greptile
jvsena42
marked this pull request as draft
August 10, 2026 10:11
jvsena42
marked this pull request as ready for review
August 10, 2026 11:33
Member
Author
|
checking CI failures Edit: both are backend failures |
17 tasks
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
jvsena42
marked this pull request as draft
August 12, 2026 17:17
This comment was marked as resolved.
This comment was marked as resolved.
jvsena42
marked this pull request as ready for review
August 13, 2026 09:54
Member
Author
|
All test passing. Re-runned manual tests checklist with journeys |
ovitrif
approved these changes
Aug 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1060
This PR:
Description
Trezor keeps no record of its hidden wallets and forgets a passphrase with the session, so Bitkit watches each one by its extended public keys and asks for the passphrase again whenever a session has to be rebuilt. The passphrase is never persisted or logged, and both entry screens block screenshots and screen recording the same way the wallet's own passphrase screens do.
A device previously mapped to a single wallet. It now maps to one identity per passphrase, keyed by the wallet id derived from its accounts rather than by the transport id, which two identities on the same device share. Watchers, balances, activity, labels and removal all follow that identity, and removing one hidden wallet leaves the others paired.
Pairing a hidden wallet adds an entry next to the standard one instead of replacing it. The device is matched by shared key material, so re-reading accounts updates the right entry while a different passphrase creates a new one. Only the identity that currently holds the device session shows as connected, since only that one can sign.
Before signing a transfer, Bitkit reopens the hidden wallet and accepts the session only if its accounts resolve back to the wallet being spent from. A wrong passphrase is not rejected by the device — it silently derives another wallet — so the mismatch is caught, the stray wallet that reading its accounts created is dropped, and the transfer fails instead of signing from the wrong wallet. A session that is still open signs with no prompt.
Discovery skips devices that are already paired, which left the Add Hardware Wallet button searching forever and made the passphrase step unreachable after the first pairing. It now falls back to offering a known reachable device once no new one is found.
Separately, the Bridge transport used for the emulator offered a released session id as the previous one when re-acquiring, and the bridge answered
wrong previous session. Since switching to a passphrase wallet closes and reopens the session, this blocked every passphrase pairing after the first. This only affects builds with the Bridge enabled; USB and BLE are unaffected.Preview
no-wallet-add-with-passphrase.webm
Add.multiple.passphrase.wallets.webm
add-repeated-passphrase-wallet.webm
passphrase-disabled.webm
remove-wallet.webm
rename-wallet.webm
transfer-current-session.webm
transfer-other-section.mp4
QA Notes
Needs a Trezor with passphrase protection enabled. On the emulator start it with
TREZOR_PASSPHRASE_PROTECTION=true ../bitkit-docker/scripts/trezor-emulator startand confirm on the device for every account a passphrase session reads, otherwise the call blocks until it times out.Manual Tests
regression:Pair a device without using the Passphrase path: home tile, detail screen, rename, remove and Transfer To Spending behave as before.files/logs/andfiles/datastore/(release build; blocking is disabled in debug).Automated Checks
TrezorRepoTest.kt.connectWithPassphraseincluding the already-watched case and a device with passphrase protection off inHwWalletRepoTest.kt.HwConnectViewModelTest.kt.TransferViewModelTest.kt.TrezorBridgeTransportTest.kt.HwWalletRepoTest.kt,TransferViewModelTest.ktandHwConnectViewModelTest.kt.passphrase-pairing.xml,passphrase-duplicate.xml,passphrase-settings-remove.xmlandpassphrase-transfer-to-spending.xml, including checks that the passphrase never reaches the logs or datastore.Known gaps